#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#include <unistd.h>
#include <fcntl.h>
#include <cJSON.h>
#include <sys/ioctl.h>
#include "Element.h"
#include <time.h>
#include <curl/curl.h>


/*共享内存申请标记*/
#define PERM S_IRUSR|S_IWUSR

int play_flag;
/*孙子进程id号*/
pid_t gradchild;

/*子进程id号*/
pid_t pid;

/*共享内存描述标记*/
int shmid;
char *p_addr;
int startplay = 0;
int FM_flag = 0;

int get_FMurl(int fm_count, MUSIC *music);
int resume(char *url) ;

int sql_find(int id, MUSIC *music) {
  sqlite3 *db = NULL;
  char *errMsg;
  int rc;
  char sql_string[64];
  char **azResult; //二维数组存放结果
  sprintf(sql_string, "select * from player where  (id=%d);", id);
  int row = 0, column = 0;
  rc = sqlite3_open("/MyDB/Music.db", &db);
  if ( rc )    {
    sqlite3_close(db);
    return row;
  }
  sqlite3_get_table(db , sql_string , &azResult , &row , &column , &errMsg);
  if (row <= 0) {
    return 0;
  }
  sprintf(music->id , "%s", azResult[column]);
  sprintf(music->name , "%s", azResult[column + 1]);
  sprintf(music->player , "%s", azResult[column + 2]);
  sprintf(music->path , "%s", azResult[column + 3]);
  return row;
}

void play(MUSIC *music)
{
  pid_t fd;
  char *c_addr;
  char *p;
  int len;
  while (play_flag)
  {
    /*创建子进程，即孙子进程*/
    fd = fork();
    if (fd == -1)
    {
      perror("fork");
      exit(1);
    }
    else if (fd == 0) //孙子进程
    {
      char Msg[50];
      //sprintf(Msg, "$shell rhythmbox %s &", music->path);
      printf("%s\n", music->path);
      //system(Msg);
      printf("music name = %s play_flager = %s\n", music->name, music->player);

      execl("/usr/bin/mplayer", "mplayer", music->path, NULL); //播放当前列表MP3音乐
      //sleep(100);
      printf("\n\n\n");
    }
    else //子进程
    {
      /*内存映射*/
      c_addr = shmat(shmid, 0, 0);

      /*把孙子进程的id和当前播放歌曲的节点指针传入共享内存*/
      memcpy(c_addr, &fd, sizeof(pid_t));

      if (fd == wait(NULL))
      {
        if (FM_flag)
        {
          int id = (int)music->id[0] - '0';
          get_FMurl(id, music);
        } else {
          play_flag = 0;
          int id = (int)music->id[0] - '0';
          printf("music->id %d\n",id);
        }
      }
    }
  }
}

void stop_Music(pid_t g_pid)
{
  if (startplay) {
    printf("+-------------------- STOPPED --------------------+\n");
    kill(g_pid, SIGKILL); //对孙子进程发送SIGKILL信号
    kill(pid, SIGKILL);  //对子进程发送SIGKILL信号
    startplay = 0;
  }
}

void pause_Music(pid_t pid)
{
  printf("+-------------------- PAUSED--------------------+\n");
  kill(pid, SIGSTOP); //对孙子进程发送SIGSTOP信号
  play_flag = 0;
}

void conti_play(pid_t pid)
{
  printf("+-------------------- CONTINUE --------------------+\n");
  kill(pid, SIGCONT); //对孙子进程发送SIGCONT信号
  play_flag = 1;
}

int play_Music(pid_t *childpid, MUSIC *music) {
  pid_t pid;
  int ret;
  pid = fork();

  if (pid > 0)
  {
    *childpid = pid; //子进程PID初始化
    play_flag = 1;
    sleep(1);
    /*读取共享内存保存的pid,初始化孙子进程的pid*/
    memcpy(&gradchild, p_addr, sizeof(pid_t));
  }
  else if (0 == pid) //子进程
  {
    /*子进程播放MP3函数*/
    play(music);
    printf("+-------------------- PLAY --------------------+\n");
  }
  return 0;
}

#define STOP  0
#define PAUSE 1
#define CONTI 2
#define PLAY 3
#define URL 4
#define FM 5
#define COM_NUM 7
#define NC  (COM_NUM-1)
#define READ_ID 254
#define READ_URL 244
#define READ_FM 234

void command_Music(int com, int fd) {
  int id;
  MUSIC music;
  FM_flag = 0;
  switch (com) {
  case STOP: stop_Music(gradchild); break; //stop
  case PAUSE: pause_Music(gradchild); break; //pause
  case CONTI: conti_play(gradchild); break; //conti
  case PLAY: {       //play
    ioctl(fd, READ_ID, 0);
    read(fd, &id, sizeof(id));
    if (startplay) {
      stop_Music(gradchild);
    }
    if (sql_find(id, &music) > 0) {
      play_flag = 1;
      play_Music(&pid, &music);
      startplay = 1;
    }
  } break;
  case URL: {
    char str[100];
    ioctl(fd, READ_URL, 0);
    read(fd, str, 100);
    if (startplay) {
      stop_Music(gradchild);
    }
    sprintf(music.path, "%s", str);
    printf("music path = %s\n", music.path);
    if (resume(str)) {
      play_flag = 1;
      play_Music(&pid, &music);
      startplay = 1;
    }
  } break;
  case FM: {
    ioctl(fd, READ_FM, 0);
    read(fd, &id, sizeof(id));
    if (startplay) {
      stop_Music(gradchild);
    }
    if ((id < 4) && (get_FMurl(id, &music))) {
      play_flag = 1;
      play_Music(&pid, &music);
      startplay = 1;
      FM_flag = 1;
    }
  } break;
  case NC: break;
  }
}

int main(void) {
  int fd;
  int com;
  int old_id = 0;
  fd = open("/dev/MX", O_RDWR, 664);
  if (fd < 0) {
    printf("can't open\n");
    return -1;
  }
  /*共享内存：用于存放子进程ID，播放列表位置*/
  if ((shmid = shmget(IPC_PRIVATE, 1, PERM)) == -1)
    exit(1);
  p_addr = shmat(shmid, 0, 0);
  memset(p_addr, '\0', 1024);
  while (1) {
    read(fd, &com, 4);
    if (com < COM_NUM) {
      command_Music(com, fd);
      com = NC;
      write(fd, &com, 4);
    }
    sleep(1);
  }
  stop_Music(gradchild);
  close(fd);
  return 0;
}


//这个函数为CURLOPT_HEADERFUNCTION参数构造
/* 从http头部获取文件size*/
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
  int r;
  long len = 0;

  /* _snscanf() is Win32 specific */
  r = sscanf(ptr, "Content-Length: %ld\n", &len);
  if (r) /* Microsoft: we don't read the specs */
    *((long *) stream) = len;

  return size * nmemb;
}

/* 保存下载文件 */
size_t wirtefunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  return fwrite(ptr, size, nmemb, stream);
}

/*读取上传文件 */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  FILE *f = stream;
  size_t n;

  if (ferror(f))
    return CURL_READFUNC_ABORT;

  n = fread(ptr, size, nmemb, f) * size;

  return n;
}

// 下载 或者上传文件函数
int download(CURL *curlhandle, const char * remotepath, const char * localpath, long timeout, long tries)
{
  FILE *f;
  curl_off_t local_file_len = -1 ;
  long filesize = 0 ;

  CURLcode r = CURLE_GOT_NOTHING;
  int c;
  struct stat file_info;
  int use_resume = 0;
  /* 得到本地文件大小 */
  //if(access(localpath,F_OK) ==0)

  if (stat(localpath, &file_info) == 0)
  {
    local_file_len =  file_info.st_size;
    use_resume  = 1;
  }
  //采用追加方式打开文件，便于实现文件断点续传工作
  f = fopen(localpath, "ab+");
  if (f == NULL) {
    perror(NULL);
    return 0;
  }

  //curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);

  curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);

  curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, timeout);  // 设置连接超时，单位秒
  //设置http 头部处理函数
  curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
  curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);
// 设置文件续传的位置给libcurl
  curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume ? local_file_len : 0);

  curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);
  curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);

  //curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
  //curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);
  curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);
  curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);


  r = curl_easy_perform(curlhandle);


  fclose(f);

  if (r == CURLE_OK)
    return 1;
  else {
    fprintf(stderr, "%s\n", curl_easy_strerror(r));
    return 0;
  }
}

int resume(char *url) {
  CURL *curlhandle = NULL;

  curl_global_init(CURL_GLOBAL_ALL);
  curlhandle = curl_easy_init();

  remove("/www/cache/cache.mp3");
  int dowload_flag = download(curlhandle , url, "/work/www/cache/1.mp3", 1, 3);
  curl_easy_cleanup(curlhandle);
  curl_global_cleanup();

  return dowload_flag;
}

int get_FMurl(int fm_count, MUSIC *music) {
  char path[30];
  int download_flag = 0;
  sprintf(path, "../tables/FM%d.json", fm_count);
  printf("path = %s\n", path);
  printf("fm_count = %d\n", fm_count );
  FILE *file = fopen(path, "r");
  if (file == NULL) {
    printf("open is error \n");
    return 0;
  }
  printf("open is over\n");
  char JMsg[1024 * 60];
  char *Json = JMsg;
  while (fread(Json, 1, 10, file)) {
    Json += 10;
  }
  fclose(file);
  cJSON *pJson = cJSON_Parse(JMsg);
  cJSON *pArray = cJSON_GetObjectItem(pJson, "tracks");
  int iCount = cJSON_GetArraySize(pArray);
  srand((int) time(0));
  int i = rand() % (iCount - 1);
  printf("iCount = %d rand = %d i=%d\n ", iCount, rand(), i );
  cJSON* pItem = cJSON_GetArrayItem(pArray, i);
  char* title = cJSON_GetObjectItem(pItem, "title")->valuestring;
  char* uid = cJSON_GetObjectItem(pItem, "uid")->valuestring;
  char* play_url = cJSON_GetObjectItem(pItem, "play_url")->valuestring;
  //printf("title = %s uid = %s play_url = %s\n",title,uid,play_url);

  sprintf(music->path, "%s", "/work/www/cache/cache.mp3");
  printf("play_url = %s\n", music->path);

  CURL *curlhandle = NULL;

  curl_global_init(CURL_GLOBAL_ALL);
  curlhandle = curl_easy_init();

  remove("/work/www/cache/cache.mp3");
  download_flag = download(curlhandle , play_url, "/work/www/cache/cache.mp3", 1, 3);
  curl_easy_cleanup(curlhandle);
  curl_global_cleanup();
  return download_flag;
}
